/***************************************************************************************
 The copyright in this software is being made available under the BSD License, included
 below. This software may be subject to other third party rights,including patent rights,
 and no such rights are granted under this license.

 Regents of the Tsinghua University, Peking University, Zhejiang University, HKUST
 Tsinghua University, Peking University, Zhejiang University, HKUST 2011

 Copyright (c) 2011, Regents of the Tsinghua University, Peking University, Zhejiang
 University, HKUST. All Rights Reserved.

 Redistribution and use in source and binary forms, with or without modification, are
 permitted provided that the following conditions are met:
   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the names of the copyright holders nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 OF SUCH DAMAGE.
***************************************************************************************/

#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <memory.h>

#include "contributors.h"
#include "global.h"
#include "memalloc.h"
#include "block.h"

#ifdef FastME
#include "fast_me.h"
extern int bipred_flag;
#endif

static int max_mvd;
int *spiral_search_x;  //  For extern use in FastME.
int *spiral_search_y;  //  For extern use in FastME.
int *mvbits;
int *byte_abs;      //  For extern use in FastME.
static const int postion[2][2] = {{0, 1}, {2, 3}};//[y][x]
#if QUARTER_PIXEL
static const int positionQ[4][4] = {{0, 4, 1, 5}, {6, 8, 14, 9}, {2, 12, 3, 13}, {7, 10, 15, 11}};  //dw 20110808
#endif
const int blk_offset_x[5][4] = {{0,0,0,0},{0,0,0,0},{0,1,0,1}};
const int blk_offset_y[5][4] = {{0,0,0,0},{0,0,0,0},{0,0,1,1}};
const int mode_blk_num[6]    = {-1, 1, 2, 2, 4, 16};

static get_pred_mv_t get_pred_mv[2];
int get_bid_cost( int org_start_x, int org_start_y, byte** bi_ref[2], int ref_start_x[2], int ref_start_y[2], int x_size, int y_size );
static void set_b_mv( mv_t* mv, bi_mv_t bi_mv, int dir );
static int full_pel_block_me( int pic_pix_y, int pic_pix_x, int blocktype, mv_t *pred_mv, mv_t *mv );
static int sub_pel_block_me( int pic_pix_y, int pic_pix_x, int blocktype, mv_t *pred_mv, mv_t *mv, int min_cost );

//xy_110506 begin
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

static void get_pred_mv_p( mv_t *pred_mv, int ref_idx, int mb_pix_x, int mb_pix_y, int mode )
{
    mv_t mva, empty_mv= {0, 0, -1};
    int  mb_available_left ;
    int  block_available_left;
    int pic_block_x = img->block8_x + ( mb_pix_x>>3 );
    int pic_block_y = img->block8_y + ( mb_pix_y>>3 );
    macroblock_t* currMB, *leftMB;

    pred_mv = ( mv_t* ) pred_mv;
    currMB  = &img->mb_data[img->curr_mb_nr];
    if ( img->curr_mb_nr >= 1 )
    {
        leftMB = &img->mb_data[img->curr_mb_nr - 1];
        mb_available_left = ( img->mb_x == 0 ) ? 0 : ( currMB->slice_nr == leftMB->slice_nr );
    }
    else
    {
        leftMB = NULL;
        mb_available_left = 0;
    }


    block_available_left = mb_available_left || ( mb_pix_x > 0 );

    if ( block_available_left )
    {
        //add the probable conditions
        if( mb_pix_x == 0 ) //use the left mb's mv
        {
            switch ( leftMB->mb_type )
            {
                case SKIP:
                    mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-2];
                    break;

                case INTER16x16:
                    mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-2];
                    break;

                case INTER8x8:
                    switch ( leftMB->subblock_type[2*( mb_pix_y/8 )+1] )
                    {
                        case SUBBLOCK_INTER8x8:
                            mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-1];
                            break;

                        case SUBBLOCK_INTER4x4:
                            mva = frm_mv_4x4[MAX_REF_NUM][pic_block_y][img->block8_x-1][( mb_pix_y%8 )/4][1];
                            break;

                        default:
                            mva = empty_mv;
                    }

                    break;

                default:
                    mva = empty_mv;
            }
        }
        else
        {
            switch ( mode )
            {
                case INTER8x8:
                    if( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER8x8 ) //left block
                        mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-1];
                    else if ( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER4x4 )
                        mva = frm_mv_4x4[MAX_REF_NUM][pic_block_y][pic_block_x-1][( mb_pix_y%8 )/4][1];
                    else
                        mva = empty_mv;
                    break;

                case INTER4x4:
                    if( mb_pix_x!=8 )
                        mva = frm_mv_4x4[MAX_REF_NUM][pic_block_y][pic_block_x][( mb_pix_y%8 )/4][0];
                    else
                    {
                        if( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER8x8 )
                            mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-1];
                        else if ( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER4x4 )
                            mva = frm_mv_4x4[MAX_REF_NUM][pic_block_y][pic_block_x-1][( mb_pix_y%8 )/4][1];
                        else
                            mva = empty_mv;
                    }
                    break;

                default:
                    mva = empty_mv;
            }
        }
    }
    else
    {
        mva = empty_mv;
    }

    *pred_mv = mva;
    pred_mv->ref = ref_idx;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void get_pred_mv_b( mv_t *pred_mv, int ref_idx, int mb_pix_x, int mb_pix_y, int mode )
{
    mv_t mva, empty_mv= {0, 0, -1};
    int  mb_available_left ;
    int  block_available_left;
    int pic_block_x = img->block8_x + ( mb_pix_x>>3 );
    int pic_block_y = img->block8_y + ( mb_pix_y>>3 );
    macroblock_t* currMB, * leftMB;

    pred_mv = ( mv_t* )pred_mv;
    currMB  = &img->mb_data[img->curr_mb_nr];
    if ( img->curr_mb_nr >= 1 )
    {
        leftMB = &img->mb_data[img->curr_mb_nr - 1];
        mb_available_left = ( img->mb_x == 0 ) ? 0 : ( currMB->slice_nr == leftMB->slice_nr );
    }
    else
    {
        leftMB = NULL;
        mb_available_left = 0;
    }

    block_available_left = mb_available_left || ( mb_pix_x > 0 );

    if ( block_available_left )
    {
        //add the probable conditions
        if( mb_pix_x == 0 ) //use the left mb's mv
        {
            switch ( leftMB->mb_type )
            {
                case SKIP:
                    set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-2], ref_idx );
                    break;

                case INTER16x16:
                    set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-2], ref_idx );
                    break;

                case INTER8x8:
                    switch ( leftMB->subblock_type[2*( mb_pix_y/8 )+1] )
                    {
                        case SUBBLOCK_INTER8x8:
                            set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-1], ref_idx );
                            break;

                        case SUBBLOCK_INTER4x4:
                            set_b_mv( &mva, frm_bi_mv_4x4[pic_block_y][img->block8_x-1][( mb_pix_y%8 )/4][1], ref_idx );
                            break;

                        default:
                            mva = empty_mv;
                    }
                    break;

                default:
                    mva = empty_mv;
            }
        }

        else
        {
            switch ( mode )
            {
                case SUBBLOCK_INTER8x8:
                    if( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER8x8 ) //left block
                        set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-1], ref_idx );
                    else if ( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER4x4 )
                        set_b_mv( &mva, frm_bi_mv_4x4[pic_block_y][pic_block_x-1][( mb_pix_y%8 )/4][1], ref_idx );
                    else
                        mva = empty_mv;
                    break;

                case SUBBLOCK_INTER4x4:
                    if( mb_pix_x!=8 )
                        set_b_mv( &mva, frm_bi_mv_4x4[pic_block_y][pic_block_x][( mb_pix_y%8 )/4][0], ref_idx );
                    else
                    {
                        if( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER8x8 )
                            set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-1], ref_idx );
                        else if ( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER4x4 )
                            set_b_mv( &mva, frm_bi_mv_4x4[pic_block_y][pic_block_x-1][( mb_pix_y%8 )/4][1], ref_idx );
                        else
                            mva = empty_mv;
                    }
                    break;

                default:
                    mva = empty_mv;
            }
        }
    }
    else
    {
        mva = empty_mv;
    }

    *pred_mv = mva;
    pred_mv->ref = ref_idx;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int blk4x4_me( int ref_idx, int pic_pix_x, int pic_pix_y, int blocktype,int block_y, int block_x, int blk4x4_y, int blk4x4_x )
{
    int min_cost  = MAX_VALUE;
    int mb_pix_x  = pic_pix_x - img->pix_x;
    int mb_pix_y  = pic_pix_y - img->pix_y;
    int b8_x      = ( mb_pix_x >> 3 );
    int b8_y      = ( mb_pix_y >> 3 );

    mv_t *pred_mv = &img->pred_mv[ref_idx][blocktype][b8_y][b8_x];
    mv_t mv;
    int list = ( img->type==B_IMG&&ref_idx!=0 )?1:0;

    get_pred_mv[img->type-1]( pred_mv, ref_idx, mb_pix_x, mb_pix_y, blocktype );
#if QUARTER_PIXEL
    mv.x      = ROUNDING( pred_mv->x );
    mv.y      = ROUNDING( pred_mv->y );
#else
    mv.x      = pred_mv->x >> 1;
    mv.y      = pred_mv->y >> 1;
#endif
    mv.ref    = ref_idx;
#ifdef FastME
    if ( input->UseFME == 1 )
        min_cost = FastIntegerPelBlockMotionSearch( ref_idx, list, pic_pix_x,pic_pix_y, blocktype, pred_mv, &mv, input->search_range );
    else
#endif
        min_cost = full_pel_block_me( pic_pix_y, pic_pix_x, blocktype , pred_mv , &mv );
    min_cost = sub_pel_block_me ( pic_pix_y, pic_pix_x, blocktype , pred_mv , &mv , min_cost );
    //save all the motion vectors
    img->mv_4x4[ref_idx][2*block_y+block_x][2*blk4x4_y+blk4x4_x]    = mv;
    img->mvd_4x4[ref_idx][2*block_y+block_x][2*blk4x4_y+blk4x4_x].x = mv.x - pred_mv->x;
    img->mvd_4x4[ref_idx][2*block_y+block_x][2*blk4x4_y+blk4x4_x].y = mv.y - pred_mv->y;

    return min_cost;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int blk_me( int ref_idx, int pic_pix_x, int pic_pix_y, int blocktype )
{
    int i, j;
    int min_cost  = MAX_VALUE;
    int mb_pix_x  = pic_pix_x - img->pix_x;
    int mb_pix_y  = pic_pix_y - img->pix_y;
    int b8_x      = ( mb_pix_x >> 3 );
    int b8_y      = ( mb_pix_y >> 3 );
    int bsx       = input->blk_size[blocktype][0];
    int bsy       = input->blk_size[blocktype][1];
    mv_t *pred_mv = &img->pred_mv[ref_idx][blocktype][b8_y][b8_x];
    mv_t mv;
    int list = ( img->type==B_IMG&&ref_idx!=0 )?1:0;

    get_pred_mv[img->type-1]( pred_mv, ref_idx, mb_pix_x, mb_pix_y,blocktype );
#if QUARTER_PIXEL
    mv.x      = ROUNDING( pred_mv->x );
    mv.y      = ROUNDING( pred_mv->y );
#else
    mv.x      = pred_mv->x >> 1;
    mv.y      = pred_mv->y >> 1;
#endif
    mv.ref    = ref_idx;
#ifdef FastME
    if ( input->UseFME == 1 )
        min_cost = FastIntegerPelBlockMotionSearch( ref_idx, list, pic_pix_x,pic_pix_y, blocktype, pred_mv, &mv, input->search_range );
    else
#endif
        min_cost = full_pel_block_me( pic_pix_y, pic_pix_x, blocktype , pred_mv , &mv );
    min_cost = sub_pel_block_me ( pic_pix_y, pic_pix_x, blocktype , pred_mv , &mv , min_cost );
    //save all the motion vectors
    for ( j = b8_y; j < b8_y+( bsy >> 3 ); j++ )
    {
        for ( i = b8_x; i < b8_x+( bsx >> 3 ); i++ )
        {
            img->mv[ref_idx][blocktype][j][i]    = mv;
            img->mvd[ref_idx][blocktype][j][i].x = mv.x - pred_mv->x;
            img->mvd[ref_idx][blocktype][j][i].y = mv.y - pred_mv->y;
        }
    }
    return min_cost;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void set_b_mv( mv_t* mv, bi_mv_t bi_mv, int dir )
{
    if ( dir == FW )
    {
        if ( bi_mv.fw_mv.ref != -1 )
        {
            *mv = bi_mv.fw_mv;
        }
        else
        {
            mv->ref = 0;
            mv->x = 0;
            mv->y = 0;

        }
    }
    else //bw
    {
        if ( bi_mv.bw_mv.ref != -1 )
        {
            *mv = bi_mv.bw_mv;
        }
        else
        {
            mv->ref = 1;
            mv->x = 0;
            mv->y = 0;
        }
    }
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void init_me_module()
{
    int bits, i, imin, imax, k, l;
    int search_range      = input->search_range;
    int max_search_points = ( 2 * search_range + 1 ) * ( 2 * search_range + 1 );

#if QUARTER_PIXEL
    int sub_pel_num       = 8 * ( 2 * search_range + 3 ); //dw need consideration
#else
    int sub_pel_num       = 4 * ( 2 * search_range + 3 );
#endif
    int max_mv_bits       = 3 + 2 * ( int )ceil( log( sub_pel_num + 1 ) / log( 2 ) + 1e-10 );

    max_mvd = ( 1 << ( ( max_mv_bits >> 1 ) ) ) - 1;

    if ( ( spiral_search_x = ( int * )calloc( max_search_points, sizeof( int ) ) ) == NULL )
        no_mem_exit( "init_me_module: spiral_search_x" );
    if ( ( spiral_search_y = ( int * )calloc( max_search_points, sizeof( int ) ) ) == NULL )
        no_mem_exit( "init_me_module: spiral_search_y" );
    if ( ( mvbits = ( int * )calloc( 2 * max_mvd + 1, sizeof( int ) ) ) == NULL )
        no_mem_exit( "init_me_module: mvbits" );
    if ( ( byte_abs = ( int * )calloc( 512, sizeof( int ) ) ) == NULL )
        no_mem_exit( "init_me_module: byte_abs" );

    byte_abs += 256;
    mvbits   += max_mvd;
    mvbits[0] = 1;

    for ( bits = 3; bits <= max_mv_bits; bits += 2 )
    {
        imax = 1 << ( bits >> 1 );
        imin = imax >> 1;
        for ( i = imin; i < imax; i++ )
            mvbits[-i] = mvbits[i] = bits;
    }
    byte_abs[0] = 0;

    for ( i = 1; i < 256; i++ )
        byte_abs[i] = byte_abs[-i] = i;
    spiral_search_x[0] = spiral_search_y[0] = 0;
    for ( k = 1, l = 1; l <= RFM_MAX( 1, search_range ); l++ )
    {
        for ( i = -l + 1; i < l; i++ )
        {
            spiral_search_x[k]   = i;
            spiral_search_y[k++] = -l;
            spiral_search_x[k]   = i;
            spiral_search_y[k++] = l;
        }
        for ( i = -l; i <= l; i++ )
        {
            spiral_search_x[k]   = -l;
            spiral_search_y[k++] = i;
            spiral_search_x[k]   = l;
            spiral_search_y[k++] = i;
        }
    }
    get_pred_mv[0] = get_pred_mv_p;
    get_pred_mv[1] = get_pred_mv_b;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void clear_me_module()
{
    mvbits   -= max_mvd;
    byte_abs -= 256;

    free( spiral_search_x );
    free( spiral_search_y );
    free( mvbits );
    free( byte_abs );
}
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int get_sad_of_one_point( byte** org, int org_start_x, int org_start_y, byte** ref, int ref_start_x, int ref_start_y, int x_size, int y_size )
{
    int y, x;
    int sad = 0;
    ref_start_y += IMG_PAD_SIZE;
    ref_start_x += IMG_PAD_SIZE;
    for ( y=0; y<y_size; y++ )
    {
        for ( x=0; x<x_size; x++ )
        {
            sad += byte_abs[org[org_start_y+y][org_start_x+x] - ref[ref_start_y+y][ref_start_x+x]];
            //sad += img->quad[org[org_start_y+y][org_start_x+x] - ref[ref_start_y+y][ref_start_x+x]];
        }
    }
    return sad;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int full_pel_block_me( int pic_pix_y, int pic_pix_x, int blocktype, mv_t *pred_mv, mv_t *mv )
{
    //incoming is integer pixel accuracy
    //output is half pixel accuracy
    int pos, target_x, target_y, cost;
    int best_pos     = 0;
    int search_range = input->search_range;
    int max_pos      = ( 2 * search_range + 1 ) * ( 2 * search_range + 1 );
    int blocksize_y  = input->blk_size[blocktype][1];
    int blocksize_x  = input->blk_size[blocktype][0];
#if QUARTER_PIXEL
    int pred_x       = pic_pix_x + ROUNDING( pred_mv->x );
    int pred_y       = pic_pix_y + ROUNDING( pred_mv->y );
#else
    int pred_x       = pic_pix_x + ( pred_mv->x >> 1 );
    int pred_y       = pic_pix_y + ( pred_mv->y >> 1 );
#endif
    int mb_pix_x     = pic_pix_x - img->pix_x;
    int mb_pix_y     = pic_pix_y - img->pix_y;
    int min_cost     = MAX_VALUE;
    byte **ref_frm   = img_y_rec_space[pred_mv->ref];

    for ( pos = 0; pos < max_pos; pos++ )
    {
        target_x = pred_x + spiral_search_x[pos];
        target_y = pred_y + spiral_search_y[pos];
        //make sure mv not exceed the PADDING size
        if ( target_x > img->p_width-blocksize_x -  IMG_PAD_SIZE || target_y > img->p_height-blocksize_y -  IMG_PAD_SIZE|| target_x < -IMG_PAD_SIZE || target_y < - IMG_PAD_SIZE )
            //let search range smaller
            //if (target_x > img->p_width-blocksize_x -  IMG_PAD_SIZE - IMG_PAD_SIZE || target_y > img->p_height-blocksize_y -  IMG_PAD_SIZE - IMG_PAD_SIZE|| target_x < -IMG_PAD_SIZE + IMG_PAD_SIZE|| target_y < - IMG_PAD_SIZE + IMG_PAD_SIZE)
        {
            continue;
        }
#if QUARTER_PIXEL
        cost = MV_COST( img->lambda_motion_factor, 2, target_x, target_y, pred_x, pred_y );
#else
        cost = MV_COST( img->lambda_motion_factor, 1, target_x, target_y, pred_x, pred_y );
#endif
        if ( cost >= min_cost )
            continue;
        cost += get_sad_of_one_point( img->org_y_data, mb_pix_x, mb_pix_y, ref_frm, target_x, target_y, blocksize_x, blocksize_y );
        if ( cost < min_cost )
        {
            best_pos  = pos;
            min_cost = cost;
        }
    }

    if ( best_pos )
    {
        mv->x += spiral_search_x[best_pos];
        mv->y += spiral_search_y[best_pos];
    }
#if QUARTER_PIXEL
    mv->x <<= 2;
    mv->y <<= 2;
#else
    mv->x <<= 1;
    mv->y <<= 1;
#endif
    return min_cost;
}


/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int full_pel_block_me_bid( int pic_pix_y, int pic_pix_x, int blocktype, mv_t *pred_mv, mv_t *pred_fix_mv, mv_t* fix_mv, mv_t *refine_mv, int min_cost )
{
    //incoming is integer pixel accuracy
    //output is half pixel accuracy
    int pos, target_x[2], target_y[2], cost, refine_ref_idx, fix_ref_idx;
    int best_pos     = 0;
    int search_range = input->search_range;
    int max_pos      = ( 2 * search_range + 1 ) * ( 2 * search_range + 1 );
    int blocksize_x  = input->blk_size[blocktype][0];
    int blocksize_y  = input->blk_size[blocktype][1];
#if QUARTER_PIXEL
    int pred_x       = pic_pix_x + ROUNDING( pred_mv->x );
    int pred_y       = pic_pix_y + ROUNDING( pred_mv->y );
    int pred_fix_x   = pic_pix_x + ROUNDING( pred_fix_mv->x );
    int pred_fix_y   = pic_pix_y + ROUNDING( pred_fix_mv->y );
#else
    int pred_x       = pic_pix_x + ( pred_mv->x >> 1 );
    int pred_y       = pic_pix_y + ( pred_mv->y >> 1 );
    int pred_fix_x   = pic_pix_x + ( pred_fix_mv->x >> 1 );
    int pred_fix_y   = pic_pix_y + ( pred_fix_mv->y >> 1 );
#endif
    int s_center_x   = pic_pix_x + refine_mv->x;  //search center
    int s_center_y   = pic_pix_y + refine_mv->y;
    int mb_pix_x     = pic_pix_x - img->pix_x;
    int mb_pix_y     = pic_pix_y - img->pix_y;
    byte **bi_ref[2];

    refine_ref_idx = pred_mv->ref;
    fix_ref_idx    = 1 - refine_ref_idx;
    bi_ref[refine_ref_idx] = img_y_rec_space[refine_ref_idx];
    bi_ref[fix_ref_idx]    = img_y_rec_space[fix_ref_idx];
    target_x[fix_ref_idx]  = pic_pix_x + fix_mv->x;
    target_y[fix_ref_idx]  = pic_pix_y + fix_mv->y;

    for ( pos = 0; pos < max_pos; pos++ )
    {
        target_x[refine_ref_idx] = s_center_x + spiral_search_x[pos];
        target_y[refine_ref_idx] = s_center_y + spiral_search_y[pos];
        //make sure mv not exceed the PADDING size
        if ( target_x[refine_ref_idx] > img->p_width-IMG_PAD_SIZE-blocksize_x || target_y[refine_ref_idx] > img->p_height-IMG_PAD_SIZE-blocksize_y || \
                target_x[refine_ref_idx] < -IMG_PAD_SIZE || target_y[refine_ref_idx] < -IMG_PAD_SIZE )
        {
            continue;
        }
#if QUARTER_PIXEL
        cost = MV_COST( img->lambda_motion_factor, 2, target_x[refine_ref_idx], target_y[refine_ref_idx], pred_x, pred_y );
        cost += MV_COST( img->lambda_motion_factor, 2, target_x[fix_ref_idx], target_y[fix_ref_idx], pred_fix_x, pred_fix_y );
#else
        cost  = MV_COST( img->lambda_motion_factor, 1, target_x[refine_ref_idx], target_y[refine_ref_idx], pred_x, pred_y );
        cost += MV_COST( img->lambda_motion_factor, 1, target_x[fix_ref_idx], target_y[fix_ref_idx], pred_fix_x, pred_fix_y );
#endif
        if ( cost >= min_cost )
            continue;
        cost += get_bid_cost( mb_pix_x, mb_pix_y, bi_ref, target_x, target_y, blocksize_x, blocksize_y );
        if ( cost < min_cost )
        {
            best_pos = pos;
            min_cost = cost;
        }
    }

    if ( best_pos )
    {
        refine_mv->x += spiral_search_x[best_pos];
        refine_mv->y += spiral_search_y[best_pos];
    }
#if QUARTER_PIXEL
    refine_mv->x <<= 2;
    refine_mv->y <<= 2;
    fix_mv->x    <<= 2;
    fix_mv->y    <<= 2;
#else
    refine_mv->x <<= 1;
    refine_mv->y <<= 1;
    fix_mv->x    <<= 1;
    fix_mv->y    <<= 1;
#endif
    return min_cost;
}
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int sub_pel_block_me( int pic_pix_y, int pic_pix_x, int blocktype, mv_t *pred_mv, mv_t *mv, int min_cost )
{
    int best_pos, pos, i, cost, target_x, target_y;
    int mb_pix_x     = pic_pix_x - img->pix_x;
    int mb_pix_y     = pic_pix_y - img->pix_y;
    int blocksize_y  = input->blk_size[blocktype][1];
    int blocksize_x  = input->blk_size[blocktype][0];
#if QUARTER_PIXEL
    int pred_x       = ( pic_pix_x<<2 ) + pred_mv->x;
    int pred_y       = ( pic_pix_y<<2 ) + pred_mv->y;
    int s_center_x   = ( pic_pix_x<<2 ) + mv->x; //search center
    int s_center_y   = ( pic_pix_y<<2 ) + mv->y;
#else
    int pred_x       = ( pic_pix_x<<1 ) + pred_mv->x;
    int pred_y       = ( pic_pix_y<<1 ) + pred_mv->y;
    int s_center_x   = ( pic_pix_x<<1 ) + mv->x; //search center
    int s_center_y   = ( pic_pix_y<<1 ) + mv->y;
#endif
    int dx,dy;
    static const int spiral_search_x[9] = {0, 1, 1, 0, -1, -1, -1, 0, 1};
    static const int spiral_search_y[9] = {0, 0,-1,-1, -1,  0,  1, 1, 1};
    best_pos  = 0;

#if QUARTER_PIXEL
    // half-pixel
    for ( i = 1; i < 9; i++ )
    {
        target_x = ( s_center_x>>1 ) + spiral_search_x[i];
        target_y = ( s_center_y>>1 ) + spiral_search_y[i];
        //make sure mv not exceed the PADDING size
        dx=target_x&1;
        dy=target_y&1;

        if ( ( target_x>>1 ) > img->p_width-blocksize_x -IMG_PAD_SIZE|| ( target_y>>1 ) > img->p_height-blocksize_y-IMG_PAD_SIZE || ( target_x>>1 ) < - IMG_PAD_SIZE || ( target_y>>1 ) < - IMG_PAD_SIZE )
        {
            continue;
        }
        cost  = MV_COST ( img->lambda_motion_factor, 0, target_x<<1, target_y<<1, pred_x, pred_y ); //Question1 ? 20110921 --
        //pos    = postion[RFM_ABS(target_y) & 1][RFM_ABS(target_x) & 1];
        pos   = postion[dy][dx];    //dw 20110925
        target_x=( target_x-dx )/2;
        target_y=( target_y-dy )/2;
        cost += get_sad_of_one_point( img->org_y_data, mb_pix_x, mb_pix_y, y_up_sampling[pred_mv->ref][pos-1], target_x/*>>1*/, target_y/*>>1*/, blocksize_x, blocksize_y );
        if ( cost < min_cost )
        {
            min_cost = cost;
            best_pos  = i;
        }
    }
    if ( best_pos )
    {
        mv->x += spiral_search_x[best_pos]<<1;
        mv->y += spiral_search_y[best_pos]<<1;
        s_center_x += spiral_search_x[best_pos]<<1;
        s_center_y += spiral_search_y[best_pos]<<1;
        best_pos = 0;
    }
    // quarter-pixel
    for ( i = 1; i < 9; i++ )
    {
        target_x = s_center_x + spiral_search_x[i];
        target_y = s_center_y + spiral_search_y[i];
        //make sure mv not exceed the PADDING size
        dx=target_x&3;
        dy=target_y&3;

        if ( ( target_x>>2 ) > img->p_width-blocksize_x -IMG_PAD_SIZE|| ( target_y>>2 ) > img->p_height-blocksize_y-IMG_PAD_SIZE || ( target_x>>2 ) < - IMG_PAD_SIZE || ( target_y>>2 ) < - IMG_PAD_SIZE )
        {
            continue;
        }
        cost  = MV_COST ( img->lambda_motion_factor, 0, target_x, target_y, pred_x, pred_y );
        //pos    = positionQ[RFM_ABS(target_y) & 3][RFM_ABS(target_x) & 3];
        pos   = positionQ[dy][dx];    //dw 20110925
        target_x=( target_x-dx )/4;
        target_y=( target_y-dy )/4;
        cost += get_sad_of_one_point( img->org_y_data, mb_pix_x, mb_pix_y, y_up_sampling[pred_mv->ref][pos-1], target_x/*>>1*/, target_y/*>>1*/, blocksize_x, blocksize_y );
        if ( cost < min_cost )
        {
            min_cost = cost;
            best_pos  = i;
        }
    }
#else
    for ( i = 1; i < 9; i++ )
    {
        target_x = s_center_x + spiral_search_x[i];
        target_y = s_center_y + spiral_search_y[i];
        //make sure mv not exceed the PADDING size
        dx=target_x&1;
        dy=target_y&1;

        if ( ( target_x>>1 ) > img->p_width-blocksize_x -IMG_PAD_SIZE|| ( target_y>>1 ) > img->p_height-blocksize_y-IMG_PAD_SIZE || ( target_x>>1 ) < - IMG_PAD_SIZE || ( target_y>>1 ) < - IMG_PAD_SIZE )
        {
            continue;
        }
        cost  = MV_COST ( img->lambda_motion_factor, 0, target_x, target_y, pred_x, pred_y );
        pos    = postion[RFM_ABS( target_y ) & 1][RFM_ABS( target_x ) & 1];
        target_x=( target_x-dx )/2;
        target_y=( target_y-dy )/2;
        cost += get_sad_of_one_point( img->org_y_data, mb_pix_x, mb_pix_y, y_up_sampling[pred_mv->ref][pos-1], target_x/*>>1*/, target_y/*>>1*/, blocksize_x, blocksize_y );
        if ( cost < min_cost )
        {
            min_cost = cost;
            best_pos  = i;
        }
    }
#endif

    if ( best_pos )
    {
        mv->x += spiral_search_x[best_pos];
        mv->y += spiral_search_y[best_pos];
    }
    return min_cost;
}


/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int sub_pel_block_me_bid( int pic_pix_y, int pic_pix_x, int blocktype, mv_t *pred_mv, mv_t *pred_fix_mv, mv_t fix_mv, mv_t *refine_mv, int min_cost )
{
    int best_pos, pos, i, cost, target_x[2], target_y[2], refine_ref_idx, fix_ref_idx;
    int mb_pix_x     = pic_pix_x - img->pix_x;
    int mb_pix_y     = pic_pix_y - img->pix_y;
    int blocksize_y  = input->blk_size[blocktype][1];
    int blocksize_x  = input->blk_size[blocktype][0];
#if QUARTER_PIXEL
    int pred_x       = ( pic_pix_x << 2 ) + pred_mv->x;
    int pred_y       = ( pic_pix_y << 2 ) + pred_mv->y;
    int s_center_x   = ( pic_pix_x << 2 ) + refine_mv->x;
    int s_center_y   = ( pic_pix_y << 2 ) + refine_mv->y;
#else
    int pred_x       = ( pic_pix_x << 1 ) + pred_mv->x;
    int pred_y       = ( pic_pix_y << 1 ) + pred_mv->y;
    int s_center_x   = ( pic_pix_x << 1 ) + refine_mv->x;
    int s_center_y   = ( pic_pix_y << 1 ) + refine_mv->y;
#endif
    byte** bi_ref[2];
    static const int spiral_search_x[9] = {0, 1, 1, 0, -1, -1, -1, 0, 1};
    static const int spiral_search_y[9] = {0, 0,-1,-1, -1,  0,  1, 1, 1};

    int pos_fix;

#if QUARTER_PIXEL
    assert ( !( refine_mv->x&3 ) && !( refine_mv->y&3 ) );
#else
    assert ( !( refine_mv->x&1 ) && !( refine_mv->y&1 ) );
#endif

    best_pos = 0;

    refine_ref_idx = pred_mv->ref;
    fix_ref_idx    = 1 - refine_ref_idx;

#if QUARTER_PIXEL
    target_x[fix_ref_idx] = ( pic_pix_x<<2 ) + fix_mv.x;
    target_y[fix_ref_idx] = ( pic_pix_y<<2 ) + fix_mv.y;
    //pos_fix = positionQ[RFM_ABS( (pic_pix_y<<2) + fix_mv.y) & 3][RFM_ABS( (pic_pix_x<<2) + fix_mv.x) & 3];
    pos_fix = positionQ[fix_mv.y & 3][fix_mv.x & 3];    //dw 20110925

    target_x[fix_ref_idx] >>= 2;
    target_y[fix_ref_idx] >>= 2;
#else
    target_x[fix_ref_idx] = ( pic_pix_x<<1 ) + fix_mv.x;
    target_y[fix_ref_idx] = ( pic_pix_y<<1 ) + fix_mv.y;
    pos_fix = postion[RFM_ABS( ( pic_pix_y<<1 ) + fix_mv.y ) & 1][RFM_ABS( ( pic_pix_x<<1 ) + fix_mv.x ) & 1];

    target_x[fix_ref_idx] >>= 1;
    target_y[fix_ref_idx] >>= 1;
#endif

#if QUARTER_PIXEL
    for ( i = 1; i < 9; i++ )
    {
        target_x[refine_ref_idx] = ( s_center_x>>1 ) + spiral_search_x[i];
        target_y[refine_ref_idx] = ( s_center_y>>1 ) + spiral_search_y[i];
        //make sure mv not exceed the PADDING size
        if ( ( target_x[refine_ref_idx]>>1 ) > img->p_width-blocksize_x-IMG_PAD_SIZE || ( target_y[refine_ref_idx]>>1 ) > img->p_height-blocksize_y-IMG_PAD_SIZE || ( target_x[refine_ref_idx]>>1 ) < -IMG_PAD_SIZE || ( target_y[refine_ref_idx]>>1 ) < -IMG_PAD_SIZE )
        {
            continue;
        }

        cost = MV_COST ( img->lambda_motion_factor, 0, target_x[refine_ref_idx]<<1, target_y[refine_ref_idx]<<1, pred_x, pred_y ); //Question2 ? 20110921
        cost += MV_COST ( img->lambda_motion_factor, 0, pred_fix_mv->x, pred_fix_mv->y, fix_mv.x, fix_mv.y );
        //pos  = postion[RFM_ABS(target_y[refine_ref_idx]) & 1][RFM_ABS(target_x[refine_ref_idx]) & 1];
        pos  = postion[target_y[refine_ref_idx] & 1][target_x[refine_ref_idx] & 1];    //dw 20110925


        if ( pos <= 0 )
            bi_ref[refine_ref_idx]   = img_y_rec_space[refine_ref_idx];
        else
            bi_ref[refine_ref_idx]   = y_up_sampling[refine_ref_idx][pos-1];

        bi_ref[fix_ref_idx]      = pos_fix == 0 ? img_y_rec_space[fix_ref_idx] : y_up_sampling[fix_ref_idx][pos_fix - 1];


        target_x[refine_ref_idx] >>= 1;
        target_y[refine_ref_idx] >>= 1;

        cost += get_bid_cost( mb_pix_x, mb_pix_y, bi_ref, target_x, target_y, blocksize_x, blocksize_y );
        if ( cost < min_cost )
        {
            min_cost = cost;
            best_pos  = i;
        }
    }
    if ( best_pos )
    {
        refine_mv->x += spiral_search_x[best_pos]<<1;
        refine_mv->y += spiral_search_y[best_pos]<<1;
        s_center_x += spiral_search_x[best_pos]<<1;
        s_center_y += spiral_search_y[best_pos]<<1;
        best_pos = 0;
    }
    // quarter-pixel
    for ( i = 1; i < 9; i++ )
    {
        target_x[refine_ref_idx] = s_center_x + spiral_search_x[i];
        target_y[refine_ref_idx] = s_center_y + spiral_search_y[i];
        //make sure mv not exceed the PADDING size
        if ( ( target_x[refine_ref_idx]>>2 ) > img->p_width-blocksize_x-IMG_PAD_SIZE || ( target_y[refine_ref_idx]>>2 ) > img->p_height-blocksize_y-IMG_PAD_SIZE || ( target_x[refine_ref_idx]>>2 ) < -IMG_PAD_SIZE || ( target_y[refine_ref_idx]>>2 ) < -IMG_PAD_SIZE )
        {
            continue;
        }
        cost = MV_COST ( img->lambda_motion_factor, 0, target_x[refine_ref_idx], target_y[refine_ref_idx], pred_x, pred_y );
        cost += MV_COST ( img->lambda_motion_factor, 0, pred_fix_mv->x, pred_fix_mv->y, fix_mv.x, fix_mv.y );
        //pos  = positionQ[RFM_ABS(target_y[refine_ref_idx]) & 3][RFM_ABS(target_x[refine_ref_idx]) & 3];
        pos  = positionQ[target_y[refine_ref_idx] & 3][target_x[refine_ref_idx] & 3];    //dw 20110925
        if ( pos <= 0 )
            bi_ref[refine_ref_idx]   = img_y_rec_space[refine_ref_idx];
        else
            bi_ref[refine_ref_idx]   = y_up_sampling[refine_ref_idx][pos-1];
        bi_ref[fix_ref_idx]      = pos_fix == 0 ? img_y_rec_space[fix_ref_idx] : y_up_sampling[fix_ref_idx][pos_fix - 1];
        target_x[refine_ref_idx] >>= 2;
        target_y[refine_ref_idx] >>= 2;
        cost += get_bid_cost( mb_pix_x, mb_pix_y, bi_ref, target_x, target_y, blocksize_x, blocksize_y );
        if ( cost < min_cost )
        {
            min_cost = cost;
            best_pos  = i;
        }
    }
#else
    for ( i = 1; i < 9; i++ )
    {
        target_x[refine_ref_idx] = s_center_x + spiral_search_x[i];
        target_y[refine_ref_idx] = s_center_y + spiral_search_y[i];
        pos  = postion[RFM_ABS( target_y[refine_ref_idx] ) & 1][RFM_ABS( target_x[refine_ref_idx] ) & 1];

        //make sure mv not exceed the PADDING size
        if ( ( target_x[refine_ref_idx]>>1 ) > img->p_width-blocksize_x-IMG_PAD_SIZE || ( target_y[refine_ref_idx]>>1 ) > img->p_height-blocksize_y-IMG_PAD_SIZE || ( target_x[refine_ref_idx]>>1 ) < -IMG_PAD_SIZE || ( target_y[refine_ref_idx]>>1 ) < -IMG_PAD_SIZE )
        {
            continue;
        }

        cost  = MV_COST ( img->lambda_motion_factor, 0, target_x[refine_ref_idx], target_y[refine_ref_idx], pred_x, pred_y );
        cost += MV_COST ( img->lambda_motion_factor, 0, pred_fix_mv->x, pred_fix_mv->y, fix_mv.x, fix_mv.y );

        if ( pos <= 0 )
            bi_ref[refine_ref_idx]   = img_y_rec_space[refine_ref_idx];
        else
            bi_ref[refine_ref_idx]   = y_up_sampling[refine_ref_idx][pos-1];

        bi_ref[fix_ref_idx]      = pos_fix == 0 ? img_y_rec_space[fix_ref_idx] : y_up_sampling[fix_ref_idx][pos_fix - 1];


        target_x[refine_ref_idx] >>=1;
        target_y[refine_ref_idx] >>=1;

        cost += get_bid_cost( mb_pix_x, mb_pix_y, bi_ref, target_x, target_y, blocksize_x, blocksize_y );
        if ( cost < min_cost )
        {
            min_cost = cost;
            best_pos  = i;
        }
    }
#endif
    if ( best_pos )
    {
        refine_mv->x += spiral_search_x[best_pos];
        refine_mv->y += spiral_search_y[best_pos];
    }
    return min_cost;
}


static int bid_check_one_point( int pic_pix_y, int pic_pix_x, int blocktype, bi_mv_t pred_mv, bi_mv_t *bi_mv, int min_cost )
{
    int pos, cost, target_x[2], target_y[2], ref_idx;
    int mb_pix_x     = pic_pix_x - img->pix_x;
    int mb_pix_y     = pic_pix_y - img->pix_y;
    int blocksize_y  = input->blk_size[blocktype][1];
    int blocksize_x  = input->blk_size[blocktype][0];
    int pred_x[2], pred_y[2];
    byte** bi_ref[2];

#if QUARTER_PIXEL
    pic_pix_x <<= 2;
    pic_pix_y <<= 2;
#else
    pic_pix_x <<= 1;
    pic_pix_y <<= 1;
#endif

    pred_x[FW]   = pic_pix_x + pred_mv.fw_mv.x;
    pred_y[FW]   = pic_pix_y + pred_mv.fw_mv.y;
    pred_x[BW]   = pic_pix_x + pred_mv.bw_mv.x;
    pred_y[BW]   = pic_pix_y + pred_mv.bw_mv.y;


    target_x[FW] = pic_pix_x  + bi_mv->fw_mv.x;
    target_y[FW] = pic_pix_y  + bi_mv->fw_mv.y;
    target_x[BW] = pic_pix_x  + bi_mv->bw_mv.x;
    target_y[BW] = pic_pix_y  + bi_mv->bw_mv.y;


    for ( ref_idx=0; ref_idx<2; ref_idx++ )
    {
#if QUARTER_PIXEL
        if ( ( target_x[ref_idx]>>2 ) > img->p_width-blocksize_x || ( target_y[ref_idx]>>2 ) > img->p_height-blocksize_y || ( target_x[ref_idx]>>2 ) < -blocksize_x || ( target_y[ref_idx]>>2 ) < -blocksize_y ) //dw 20110808
#else
        if ( ( target_x[ref_idx]>>1 ) > img->p_width-blocksize_x || ( target_y[ref_idx]>>1 ) > img->p_height-blocksize_y || ( target_x[ref_idx]>>1 ) < -blocksize_x || ( target_y[ref_idx]>>1 ) < -blocksize_y )
#endif
        {
            return MAX_VALUE;
        }
    }

    cost=0;
    for( ref_idx=0; ref_idx<2; ref_idx++ )
    {
        cost += MV_COST ( img->lambda_motion_factor, 0, target_x[ref_idx], target_y[ref_idx], pred_x[ref_idx], pred_y[ref_idx] );

#if QUARTER_PIXEL
        pos   = positionQ[target_y[ref_idx] & 3][target_x[ref_idx] & 3];    //dw 20110925
#else
        pos   = postion[RFM_ABS( target_y[ref_idx] ) & 1][RFM_ABS( target_x[ref_idx] ) & 1];
#endif

        if ( !pos )
        {
            bi_ref[ref_idx]   = img_y_rec_space[ref_idx];
        }
        else
        {
            bi_ref[ref_idx]   = y_up_sampling[ref_idx][pos-1];
        }

#if QUARTER_PIXEL
        target_x[ref_idx] >>= 2;
        target_y[ref_idx] >>= 2;
#else
        target_x[ref_idx] >>=1;
        target_y[ref_idx] >>=1;
#endif
    }
    cost += get_bid_cost( mb_pix_x, mb_pix_y, bi_ref, target_x, target_y, blocksize_x, blocksize_y );
    return cost;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static inline uint32_t rnd_avg32( uint32_t a, uint32_t b )
{
    return ( a | b ) - ( ( ( a ^ b ) & ~( ( 0x01 )*0x01010101UL ) ) >> 1 );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void get_bi_pred( byte pred[][16], byte** bi_ref[2], int ref_start_x[2], int ref_start_y[2], int x_size, int y_size )
{
    int y, x;
    for ( y = 0; y < y_size; y++ )
    {
        for ( x = 0; x < x_size; x+=4 )
        {
            *( ( uint32_t* )( &pred[y][x] ) ) = rnd_avg32( *( ( ( uint32_t* )( &bi_ref[0][ref_start_y[0]+y][ref_start_x[0]+x] ) ) ), *( ( uint32_t* )( &bi_ref[1][ref_start_y[1]+y][ref_start_x[1]+x] ) ) );
        }
    }
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int get_bid_cost( int org_start_x, int org_start_y, byte** bi_ref[2], int ref_start_x[2], int ref_start_y[2], int x_size, int y_size )
{
    int y, x, cost = 0;
    byte pred[16][16];
    int tmp_ref_start_x[2],tmp_ref_start_y[2];
    tmp_ref_start_x[0] = ref_start_x[0] + IMG_PAD_SIZE;
    tmp_ref_start_x[1] = ref_start_x[1] + IMG_PAD_SIZE;
    tmp_ref_start_y[0] = ref_start_y[0] + IMG_PAD_SIZE;
    tmp_ref_start_y[1] = ref_start_y[1] + IMG_PAD_SIZE;

    get_bi_pred( pred, bi_ref, tmp_ref_start_x, tmp_ref_start_y, x_size, y_size );
    for ( y = 0; y < y_size; y++ )
    {
        for ( x = 0; x < x_size; x++ )
        {
            cost +=/*img->quad*/byte_abs[img->org_y_data[org_start_y+y][org_start_x+x]-pred[y][x]];

        }
    }
    return cost;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int blk_me_bid( int ref_idx, int pic_pix_x, int pic_pix_y, int blocktype )
{
    int i, j, refine = 0;
    int min_cost  = MAX_VALUE;
    int mb_pix_x  = pic_pix_x - img->pix_x;
    int mb_pix_y  = pic_pix_y - img->pix_y;
    int b8_x      = ( mb_pix_x >> 3 );
    int b8_y      = ( mb_pix_y >> 3 );
    int bsx       = input->blk_size[blocktype][0];
    int bsy       = input->blk_size[blocktype][1];
    bi_mv_t *pred_mv = &img->bi_pred_mv[blocktype][b8_y][b8_x];
    bi_mv_t mv;
    get_pred_mv[1]( &( pred_mv->fw_mv ), FW, mb_pix_x, mb_pix_y, blocktype );
    get_pred_mv[1]( &( pred_mv->bw_mv ), BW, mb_pix_x, mb_pix_y, blocktype );
    //set the init bi direction mv to the mv gotten in the single direction me
    mv.fw_mv = img->mv[FW][blocktype][b8_y][b8_x];
    mv.bw_mv = img->mv[BW][blocktype][b8_y][b8_x];
    if ( input->bi_me )
    {

        min_cost = bid_check_one_point( pic_pix_y, pic_pix_x, blocktype, *pred_mv, &mv, MAX_VALUE );

        for ( refine = 0; refine < input->bi_me_refine; refine++ )
        {
#if QUARTER_PIXEL
            mv.fw_mv.x = ROUNDING( mv.fw_mv.x ); //dw 20110920
            mv.fw_mv.y = ROUNDING( mv.fw_mv.y ); //dw 20110920
            mv.bw_mv.x = ROUNDING( mv.bw_mv.x ); //dw 20110920
            mv.bw_mv.y = ROUNDING( mv.bw_mv.y ); //dw 20110920
#else
            mv.fw_mv.x /=2;
            mv.fw_mv.y /=2;
            mv.bw_mv.x /=2;
            mv.bw_mv.y /=2;
#endif
            if ( !( refine&1 ) ) //forward refine
            {
#ifdef FastME
                if ( input->UseFME )
                    min_cost = FastBipredIntegerPelBlockMotionSearch( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->fw_mv ), &( pred_mv->bw_mv ), &mv.bw_mv , &mv.fw_mv , min_cost );
                else
#endif
                    min_cost = full_pel_block_me_bid( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->fw_mv ), &( pred_mv->bw_mv ), &mv.bw_mv , &mv.fw_mv , min_cost );
            }
            else //backward refine
            {
#ifdef FastME
                if ( input->UseFME )
                    min_cost = FastBipredIntegerPelBlockMotionSearch( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->bw_mv ), &( pred_mv->fw_mv ), &mv.fw_mv , &mv.bw_mv , min_cost );
                else
#endif
                    min_cost = full_pel_block_me_bid( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->bw_mv ), &( pred_mv->fw_mv ), &mv.fw_mv , &mv.bw_mv , min_cost );
            }
        }

        if ( input->bi_me_refine )
        {
            min_cost = sub_pel_block_me_bid ( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->fw_mv ), &( pred_mv->bw_mv ), mv.bw_mv , &mv.fw_mv , min_cost );
            min_cost = sub_pel_block_me_bid ( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->bw_mv ), &( pred_mv->fw_mv ), mv.fw_mv , &mv.bw_mv , min_cost );
        }

    }
    else //just calculate the bi direction cost
    {
        min_cost = bid_check_one_point( pic_pix_y, pic_pix_x, blocktype, *pred_mv, &mv, MAX_VALUE );
    }
    for ( j = b8_y; j < b8_y+( bsx >> 3 ); j++ )
    {
        for ( i = b8_x; i < b8_x+( bsy >> 3 ); i++ )
        {
            img->bi_mv[blocktype][j][i] = mv;
            img->bi_mvd[blocktype][j][i].fw_mvd.x = mv.fw_mv.x - pred_mv->fw_mv.x;
            img->bi_mvd[blocktype][j][i].fw_mvd.y = mv.fw_mv.y - pred_mv->fw_mv.y;
            img->bi_mvd[blocktype][j][i].bw_mvd.x = mv.bw_mv.x - pred_mv->bw_mv.x;
            img->bi_mvd[blocktype][j][i].bw_mvd.y = mv.bw_mv.y - pred_mv->bw_mv.y;
        }
    }
    return min_cost;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int blk4x4_me_bid( int ref_idx, int pic_pix_x, int pic_pix_y, int blocktype,int block_y, int block_x, int blk4x4_y, int blk4x4_x )
{
    int refine = 0;
    int min_cost  = MAX_VALUE;
    int mb_pix_x  = pic_pix_x - img->pix_x;
    int mb_pix_y  = pic_pix_y - img->pix_y;
    int b8_x      = ( mb_pix_x >> 3 );
    int b8_y      = ( mb_pix_y >> 3 );

    bi_mv_t *pred_mv = &img->bi_pred_mv[blocktype][b8_y][b8_x];
    bi_mv_t mv;
    get_pred_mv[1]( &( pred_mv->fw_mv ), FW, mb_pix_x, mb_pix_y, blocktype );
    get_pred_mv[1]( &( pred_mv->bw_mv ), BW, mb_pix_x, mb_pix_y, blocktype );
    //set the init bi direction mv to the mv gotten in the single direction me
    mv.fw_mv = img->mv_4x4[FW][2*block_y+block_x][2*blk4x4_y+blk4x4_x];
    mv.bw_mv = img->mv_4x4[BW][2*block_y+block_x][2*blk4x4_y+blk4x4_x];
    if ( input->bi_me )
    {
        min_cost = bid_check_one_point( pic_pix_y, pic_pix_x, blocktype, *pred_mv, &mv, MAX_VALUE );
        for ( refine = 0; refine < input->bi_me_refine; refine++ )
        {
#if QUARTER_PIXEL
            mv.fw_mv.x = ROUNDING( mv.fw_mv.x ); //dw 20110920
            mv.fw_mv.y = ROUNDING( mv.fw_mv.y ); //dw 20110920
            mv.bw_mv.x = ROUNDING( mv.bw_mv.x ); //dw 20110920
            mv.bw_mv.y = ROUNDING( mv.bw_mv.y ); //dw 20110920
#else
            mv.fw_mv.x /=2;
            mv.fw_mv.y /=2;
            mv.bw_mv.x /=2;
            mv.bw_mv.y /=2;
#endif
            if ( !( refine&1 ) ) //forward refine
            {
#ifdef FastME
                if ( input->UseFME )
                    min_cost = FastBipredIntegerPelBlockMotionSearch( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->fw_mv ), &( pred_mv->bw_mv ), &mv.bw_mv , &mv.fw_mv , min_cost );
                else
#endif
                    min_cost = full_pel_block_me_bid( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->fw_mv ), &( pred_mv->bw_mv ), &mv.bw_mv , &mv.fw_mv , min_cost );
            }
            else //backward refine
            {
#ifdef FastME
                if ( input->UseFME )
                    min_cost = FastBipredIntegerPelBlockMotionSearch( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->bw_mv ), &( pred_mv->fw_mv ), &mv.fw_mv , &mv.bw_mv , min_cost );
                else
#endif
                    min_cost = full_pel_block_me_bid( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->bw_mv ), &( pred_mv->fw_mv ), &mv.fw_mv , &mv.bw_mv , min_cost );
            }
        }

        if ( input->bi_me_refine )
        {
            min_cost = sub_pel_block_me_bid ( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->fw_mv ), &( pred_mv->bw_mv ), mv.bw_mv , &mv.fw_mv , min_cost );
            min_cost = sub_pel_block_me_bid ( pic_pix_y, pic_pix_x, blocktype, &( pred_mv->bw_mv ), &( pred_mv->fw_mv ), mv.fw_mv , &mv.bw_mv , min_cost );
        }

    }
    else //just calculate the bi direction cost
    {
        min_cost = bid_check_one_point( pic_pix_y, pic_pix_x, blocktype, *pred_mv, &mv, MAX_VALUE );
    }

    img->bi_mv_4x4[2*block_y+block_x][2*blk4x4_y+blk4x4_x] = mv;
    img->bi_mvd_4x4[2*block_y+block_x][2*blk4x4_y+blk4x4_x].fw_mvd.x = mv.fw_mv.x - pred_mv->fw_mv.x;
    img->bi_mvd_4x4[2*block_y+block_x][2*blk4x4_y+blk4x4_x].fw_mvd.y = mv.fw_mv.y - pred_mv->fw_mv.y;
    img->bi_mvd_4x4[2*block_y+block_x][2*blk4x4_y+blk4x4_x].bw_mvd.x = mv.bw_mv.x - pred_mv->bw_mv.x;
    img->bi_mvd_4x4[2*block_y+block_x][2*blk4x4_y+blk4x4_x].bw_mvd.y = mv.bw_mv.y - pred_mv->bw_mv.y;

    return min_cost;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void find_skip_mv()
{
    int i, j, dir;
    mv_t tmp_mv;
    extern int best8x8ref[MAX_MODE_NUM][2][2];

#define GET_MV                                                                             \
  switch(dir)                                                                              \
  {                                                                                        \
  case FW:                                                                                 \
  get_pred_mv_b(&img->mv[FW][SKIP][0][0],/*&img->bi_mv[SKIP][0][0].fw_mv,*/ FW, 0, 0, SKIP);  \
  img->mv[FW][SKIP][1][1] = img->mv[FW][SKIP][1][0] = img->mv[FW][SKIP][0][1] = img->mv[FW][SKIP][0][0] ;\
  break;                                                                                 \
  case BW:                                                                                 \
  get_pred_mv_b(&img->mv[BW][SKIP][0][0],/*&img->bi_mv[SKIP][0][0].bw_mv,*/ BW, 0, 0, SKIP);  \
  img->mv[BW][SKIP][1][1] = img->mv[BW][SKIP][1][0] = img->mv[BW][SKIP][0][1] = img->mv[BW][SKIP][0][0] ;\
  break;                                                                                 \
  case BI:                                                                                 \
  get_pred_mv_b(&img->bi_mv[SKIP][0][0].fw_mv, FW, 0, 0, SKIP);  \
  get_pred_mv_b(&img->bi_mv[SKIP][0][0].bw_mv, BW, 0, 0, SKIP);  \
  img->bi_mv[SKIP][0][1] = img->bi_mv[SKIP][0][0] ;                                      \
  img->bi_mv[SKIP][1][0] = img->bi_mv[SKIP][0][0] ;                                      \
  img->bi_mv[SKIP][1][1] = img->bi_mv[SKIP][0][0] ;                                      \
  break;                                                                                 \
  }

    //How to decide the SKIP mv should be discussed
    //Now the SKIP mv of the first MB in one row is set to be zero as MPEG-2
    memset( img->mv, 0, 2*MAX_MODE_NUM*2*2*sizeof( mv_t ) );
    memset( img->bi_mv,0,MAX_MODE_NUM*2*2*sizeof( bi_mv_t ) );
    //use the previous mv
    if ( img->mb_x )
    {
        switch( img->type )
        {
            case P_IMG:
                for ( j=0; j<2; j++ )
                {
                    for ( i=0; i<2; i++ )
                    {
                        get_pred_mv_p( &img->mv[FW][SKIP][j][i], FW, 0, 0, SKIP );
                        best8x8ref[SKIP][j][i] = FW;
                    }
                }
                break;
            case B_IMG:

                //decide the direction according to its neighbor blocks
                //________________________________________________________________________________________//
                if ( !img->pix_x )
                {
                    //the direction is bi direction
                    //get_pred_mv_b(&img->bi_mv[SKIP][j][i], 0, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE);
                    dir = BI;
                    memset( img->bi_mv[SKIP], 0, 4*sizeof( bi_mv_t ) );
                }
                else
                {
                    //the direction is the same as the left block
                    if( input->ABTen && input->InterABTen )
                        //dir = ( img->mb_data[img->curr_mb_nr-1].mb_type == INTER4x4 ? img->mb_data[img->curr_mb_nr-1].b4_ref[1][1]: img->mb_data[img->curr_mb_nr-1].b8_ref[0][1]); //xy_110506
                        dir = ( img->mb_data[img->curr_mb_nr-1].subblock_type[1] == SUBBLOCK_INTER4x4 || img->mb_data[img->curr_mb_nr-1].subblock_type[1] == SUBBLOCK_INTRA4x4 ) ? img->mb_data[img->curr_mb_nr-1].b4_ref[1][1]: img->mb_data[img->curr_mb_nr-1].b8_ref[0][1]; //xy_110506
                    else
                        dir = img->mb_data[img->curr_mb_nr-1].b8_ref[0][1];
                    GET_MV;
                }
                //_____________________________________________________________________________________________////

                //  //decide the direction according to its neighbor blocks
                //  if (!img->pix_x && !img->pix_y)
                //  {
                //    //the direction is bi direction
                //    //get_pred_mv_b(&img->bi_mv[SKIP][j][i], 0, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE);
                //    dir = BI;
                //    memset(img->bi_mv[SKIP], 0, 4*sizeof(bi_mv_t));
                //  }
                //  else if (img->pix_x && !img->pix_y)
                //  {
                //    //the direction is the same as the left block
                //if(input->ABTen && input->InterABTen)
                // //dir = ( img->mb_data[img->curr_mb_nr-1].mb_type == INTER4x4 ? img->mb_data[img->curr_mb_nr-1].b4_ref[1][1]: img->mb_data[img->curr_mb_nr-1].b8_ref[0][1]); //xy_110506
                // dir = ( img->mb_data[img->curr_mb_nr-1].subblock_type[1] == SUBBLOCK_INTER4x4 || img->mb_data[img->curr_mb_nr-1].subblock_type[1] == SUBBLOCK_INTRA4x4) ? img->mb_data[img->curr_mb_nr-1].b4_ref[1][1]: img->mb_data[img->curr_mb_nr-1].b8_ref[0][1]; //xy_110506
                //else
                //       dir = img->mb_data[img->curr_mb_nr-1].b8_ref[0][1];
                //    GET_MV;
                //  }
                //  else if (!img->pix_x && img->pix_y)
                //  {
                //    //the direction is the same as the up block
                //if(input->ABTen && input->InterABTen)
                // dir = ( img->mb_data[img->curr_mb_nr-img->mb_width].subblock_type[2] == SUBBLOCK_INTER4x4 || img->mb_data[img->curr_mb_nr-img->mb_width].subblock_type[2] == SUBBLOCK_INTRA4x4) ? img->mb_data[img->curr_mb_nr-img->mb_width].b4_ref[2][2]: img->mb_data[img->curr_mb_nr-img->mb_width].b8_ref[1][0];//xy_110506
                //else
                //       dir = img->mb_data[img->curr_mb_nr-img->mb_width].b8_ref[1][0];
                //    GET_MV;
                //  }
                //  else
                //  {
                //    //the direction is selected as the max direction of the neighbor blocks
                //if(input->ABTen && input->InterABTen)
                //{
                // int up_dir = ( img->mb_data[img->curr_mb_nr-img->mb_width].subblock_type[2] == SUBBLOCK_INTER4x4 || img->mb_data[img->curr_mb_nr-img->mb_width].subblock_type[2] == SUBBLOCK_INTRA4x4) ? img->mb_data[img->curr_mb_nr-img->mb_width].b4_ref[2][2]: img->mb_data[img->curr_mb_nr-img->mb_width].b8_ref[1][0];//xy_110506
                // int left_dir = ( img->mb_data[img->curr_mb_nr-1].subblock_type[1] == SUBBLOCK_INTER4x4 || img->mb_data[img->curr_mb_nr-1].subblock_type[1] == SUBBLOCK_INTRA4x4) ? img->mb_data[img->curr_mb_nr-1].b4_ref[1][1]: img->mb_data[img->curr_mb_nr-1].b8_ref[0][1];//xy_110506
                // dir = RFM_MAX(left_dir, up_dir);
                //}
                //else
                //       dir = RFM_MAX(img->mb_data[img->curr_mb_nr-1].b8_ref[0][1], img->mb_data[img->curr_mb_nr-img->mb_width].b8_ref[1][0]);
                //    GET_MV;
                //  }

                img->skip_dir = dir;
                for ( j=0; j<2; j++ )
                {
                    for ( i=0; i<2; i++ )
                    {
                        best8x8ref[SKIP][j][i] = dir;
                    }

                }

                break;
        }
    }
    else
    {
        switch( img->type )
        {
            case P_IMG:
                tmp_mv.x=tmp_mv.y=0;
                tmp_mv.ref=FW;
                for ( j=0; j<2; j++ )
                {
                    for ( i=0; i<2; i++ )
                    {
                        img->mv[FW][SKIP][j][i] = tmp_mv;
                        best8x8ref[SKIP][j][i] = FW;
                    }
                }
                break;
            case B_IMG:
                tmp_mv.x=tmp_mv.y=0;
                tmp_mv.ref=FW;
                img->bi_mv[SKIP][1][1].fw_mv=img->bi_mv[SKIP][1][0].fw_mv=img->bi_mv[SKIP][0][1].fw_mv=img->bi_mv[SKIP][0][0].fw_mv = tmp_mv;

                tmp_mv.x=tmp_mv.y=0;
                tmp_mv.ref=BW;
                img->bi_mv[SKIP][1][1].bw_mv=img->bi_mv[SKIP][1][0].bw_mv=img->bi_mv[SKIP][0][1].bw_mv=img->bi_mv[SKIP][0][0].bw_mv = tmp_mv;
                for ( j=0; j<2; j++ )
                {
                    for ( i=0; i<2; i++ )
                    {
                        best8x8ref[SKIP][j][i] = BI;
                    }
                }

        }

    }
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int get_skip_mode_cost()
{
    int min_cost = MAX_VALUE, pos;
    int target_x[2], target_y[2];
    byte **ref[2];
    if ( img->type == P_IMG )
    {
#if QUARTER_PIXEL
        target_x[0] = ( img->pix_x<<2 ) + img->mv[FW][SKIP][0][0].x; //dw 20110921
        target_y[0] = ( img->pix_y<<2 ) + img->mv[FW][SKIP][0][0].y; //dw 20110921
        pos = positionQ[target_y[0] & 3][target_x[0] & 3];  //dw 20110925
#else
        target_x[0] = ( img->pix_x<<1 ) + img->mv[FW][SKIP][0][0].x;
        target_y[0] = ( img->pix_y<<1 ) + img->mv[FW][SKIP][0][0].y;
        pos = postion[RFM_ABS( target_y[0] )&1][RFM_ABS( target_x[0] )&1];
#endif
        if ( pos )
        {
            ref[0] = y_up_sampling[0][pos-1];
        }
        else
        {
            ref[0] = img_y_rec_space[SKIP_REF_INDEX];
        }
#if QUARTER_PIXEL
        target_x[0] >>= 2;
        target_y[0] >>= 2;
#else
        target_x[0] >>= 1;
        target_y[0] >>= 1;
#endif
        target_x[0]=RFM_CLIP3( target_x[0],-IMG_PAD_SIZE,( img->p_width-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) ); //to avoid skip mode ref out of range
        target_y[0]=RFM_CLIP3( target_y[0],-IMG_PAD_SIZE,( img->p_height-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) );

        min_cost = get_sad_of_one_point( img->org_y_data, 0, 0, ref[0], target_x[0], target_y[0], MB_BLOCK_SIZE, MB_BLOCK_SIZE );
    }
    else if ( img->type == B_IMG )
    {
        switch( img->skip_dir )
        {
            case FW:
#if QUARTER_PIXEL
                target_x[FW] = ( img->pix_x<<2 ) + img->mv[FW][SKIP][0][0].x; //img->bi_mv[SKIP][0][0].fw_mv.x;  //dw 20110921
                target_y[FW] = ( img->pix_y<<2 ) + img->mv[FW][SKIP][0][0].y; //img->bi_mv[SKIP][0][0].fw_mv.y;  //dw 20110921
                pos = positionQ[target_y[FW] & 3][target_x[FW] & 3];  //dw 20110925
#else
                target_x[FW] = ( img->pix_x<<1 ) + img->mv[FW][SKIP][0][0].x; //img->bi_mv[SKIP][0][0].fw_mv.x;
                target_y[FW] = ( img->pix_y<<1 ) + img->mv[FW][SKIP][0][0].y; //img->bi_mv[SKIP][0][0].fw_mv.y;
                pos = postion[RFM_ABS( target_y[FW] )&1][RFM_ABS( target_x[FW] )&1];
#endif
                if ( pos )
                {
                    ref[FW] = y_up_sampling[FW][pos-1];
                }
                else
                {
                    ref[FW] = img_y_rec_space[FW];
                }
#if QUARTER_PIXEL
                target_x[FW] >>= 2;
                target_y[FW] >>= 2;
#else
                target_x[FW] >>= 1;
                target_y[FW] >>= 1;
#endif
                target_x[FW]=RFM_CLIP3( target_x[FW],-IMG_PAD_SIZE,( img->p_width-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) ); // to avoid skip mode ref out of range
                target_y[FW]=RFM_CLIP3( target_y[FW],-IMG_PAD_SIZE,( img->p_height-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) );
                min_cost = get_sad_of_one_point( img->org_y_data, 0, 0, ref[FW], target_x[FW], target_y[FW], MB_BLOCK_SIZE, MB_BLOCK_SIZE );
                break;
            case BW:
#if QUARTER_PIXEL
                target_x[BW] = ( img->pix_x<<2 ) + img->mv[BW][SKIP][0][0].x; //img->bi_mv[SKIP][0][0].bw_mv.x;  //dw 20110921
                target_y[BW] = ( img->pix_y<<2 ) + img->mv[BW][SKIP][0][0].y; //img->bi_mv[SKIP][0][0].bw_mv.y;  //dw 20110921
                pos = positionQ[target_y[BW] & 3][target_x[BW] & 3];  //dw 20110925
#else
                target_x[BW] = ( img->pix_x<<1 ) + img->mv[BW][SKIP][0][0].x; //img->bi_mv[SKIP][0][0].bw_mv.x;
                target_y[BW] = ( img->pix_y<<1 ) + img->mv[BW][SKIP][0][0].y; //img->bi_mv[SKIP][0][0].bw_mv.y;
                pos = postion[RFM_ABS( target_y[BW] )&1][RFM_ABS( target_x[BW] )&1];
#endif
                if ( pos )
                {
                    ref[BW] = y_up_sampling[BW][pos-1];
                }
                else
                {
                    ref[BW] = img_y_rec_space[BW];
                }
#if QUARTER_PIXEL
                target_x[BW] >>= 2;
                target_y[BW] >>= 2;
#else
                target_x[BW] >>= 1;
                target_y[BW] >>= 1;
#endif
                target_x[BW]=RFM_CLIP3( target_x[BW],-IMG_PAD_SIZE,( img->p_width-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) ); //to avoid skip mode ref out of range
                target_y[BW]=RFM_CLIP3( target_y[BW],-IMG_PAD_SIZE,( img->p_height-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) );
                min_cost = get_sad_of_one_point( img->org_y_data, 0, 0, ref[BW], target_x[BW], target_y[BW], MB_BLOCK_SIZE, MB_BLOCK_SIZE );
                break;
            case BI:
#if QUARTER_PIXEL
                target_x[FW] = ( img->pix_x<<2 ) + img->bi_mv[SKIP][0][0].fw_mv.x; //dw 20110921
                target_y[FW] = ( img->pix_y<<2 ) + img->bi_mv[SKIP][0][0].fw_mv.y; //dw 20110921
                pos = positionQ[target_y[FW] & 3][target_x[FW] & 3];  //dw 20110925
#else
                target_x[FW] = ( img->pix_x<<1 ) + img->bi_mv[SKIP][0][0].fw_mv.x;
                target_y[FW] = ( img->pix_y<<1 ) + img->bi_mv[SKIP][0][0].fw_mv.y;
                pos = postion[RFM_ABS( target_y[FW] )&1][RFM_ABS( target_x[FW] )&1];
#endif
                if ( pos )
                {
                    ref[FW] = y_up_sampling[FW][pos-1];
                }
                else
                {
                    ref[FW] = img_y_rec_space[FW];
                }
#if QUARTER_PIXEL
                target_x[FW] >>= 2;
                target_y[FW] >>= 2;
#else
                target_x[FW] >>= 1;
                target_y[FW] >>= 1;
#endif
                target_x[FW]=RFM_CLIP3( target_x[FW],-IMG_PAD_SIZE,( img->p_width-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) ); // to avoid skip mode ref out of range
                target_y[FW]=RFM_CLIP3( target_y[FW],-IMG_PAD_SIZE,( img->p_height-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) );

#if QUARTER_PIXEL
                target_x[BW] = ( img->pix_x<<2 ) + img->bi_mv[SKIP][0][0].bw_mv.x; //dw 20110921
                target_y[BW] = ( img->pix_y<<2 ) + img->bi_mv[SKIP][0][0].bw_mv.y; //dw 20110921
                pos = positionQ[target_y[BW] & 3][target_x[BW] & 3];  //dw 20110925
#else
                target_x[BW] = ( img->pix_x<<1 ) + img->bi_mv[SKIP][0][0].bw_mv.x;
                target_y[BW] = ( img->pix_y<<1 ) + img->bi_mv[SKIP][0][0].bw_mv.y;
                pos = postion[RFM_ABS( target_y[BW] )&1][RFM_ABS( target_x[BW] )&1];
#endif
                if ( pos )
                {
                    ref[BW] = y_up_sampling[BW][pos-1];
                }
                else
                {
                    ref[BW] = img_y_rec_space[BW];
                }
#if QUARTER_PIXEL
                target_x[BW] >>= 2;
                target_y[BW] >>= 2;
#else
                target_x[BW] >>= 1;
                target_y[BW] >>= 1;
#endif
                target_x[BW]=RFM_CLIP3( target_x[BW],-IMG_PAD_SIZE,( img->p_width-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) ); //to avoid skip mode ref out of range
                target_y[BW]=RFM_CLIP3( target_y[BW],-IMG_PAD_SIZE,( img->p_height-MB_BLOCK_SIZE - IMG_PAD_SIZE-1 ) );
                min_cost = get_bid_cost( 0, 0, ref, target_x, target_y, MB_BLOCK_SIZE, MB_BLOCK_SIZE );
                break;
        }
    }
    return min_cost;
}
